﻿"""
主窗口视图
系统的主界面
"""

import sys
import datetime
import cv2
from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout,
                             QHBoxLayout, QPushButton, QLabel, QTableWidget,
                             QTableWidgetItem, QMessageBox, QFileDialog,
                             QDialog, QFormLayout, QLineEdit, QDialogButtonBox,
                             QTextEdit, QComboBox, QGroupBox, QSplitter)
from PyQt6.QtCore import QTimer, Qt
from PyQt6.QtGui import QImage, QPixmap, QFont, QColor
from src.controllers.attendance_controller import AttendanceController
from src.config.settings import UI_CONFIG, COLORS, BUTTON_STYLES


class MainWindow(QMainWindow):
    """主窗口"""
    
    def __init__(self):
        super().__init__()
        self.controller = AttendanceController()
        self.init_ui()
        self.setup_timer()
        self.load_initial_data()
    
    def init_ui(self):
        """初始化用户界面"""
        self.setWindowTitle(UI_CONFIG['window_title'])
        self.setGeometry(100, 100, *UI_CONFIG['window_size'])
        
        # 设置中文字体
        font = QFont(UI_CONFIG['font_family'], UI_CONFIG['font_size'])
        QApplication.setFont(font)
        
        # 创建中央部件
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        
        # 主布局
        main_layout = QHBoxLayout()
        central_widget.setLayout(main_layout)
        
        # 左侧区域
        left_widget = self.create_left_panel()
        
        # 右侧区域
        right_widget = self.create_right_panel()
        
        # 分割器
        splitter = QSplitter(Qt.Orientation.Horizontal)
        splitter.addWidget(left_widget)
        splitter.addWidget(right_widget)
        splitter.setSizes([700, 500])
        
        main_layout.addWidget(splitter)
    
    def create_left_panel(self) -> QWidget:
        """创建左侧面板"""
        left_widget = QWidget()
        left_layout = QVBoxLayout(left_widget)
        
        # 摄像头区域
        camera_group = self.create_camera_group()
        left_layout.addWidget(camera_group)
        
        # 状态信息区域
        status_group = self.create_status_group()
        left_layout.addWidget(status_group)
        
        # 功能按钮区域
        button_layout = self.create_button_layout()
        left_layout.addLayout(button_layout)
        
        return left_widget
    
    def create_camera_group(self) -> QGroupBox:
        """创建摄像头组"""
        camera_group = QGroupBox("摄像头预览")
        camera_layout = QVBoxLayout()
        
        # 摄像头显示标签
        self.camera_label = QLabel()
        self.camera_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.camera_label.setMinimumSize(*UI_CONFIG['camera_preview_size'])
        self.camera_label.setText("摄像头未开启")
        self.camera_label.setStyleSheet("border: 2px solid gray; background-color: #f0f0f0;")
        camera_layout.addWidget(self.camera_label)
        
        # 手动打卡按钮
        self.manual_check_btn = QPushButton("手动打卡")
        self.manual_check_btn.clicked.connect(self.manual_check_in)
        self.manual_check_btn.setStyleSheet(BUTTON_STYLES['error'])
        camera_layout.addWidget(self.manual_check_btn)
        
        camera_group.setLayout(camera_layout)
        return camera_group
    
    def create_status_group(self) -> QGroupBox:
        """创建状态组"""
        status_group = QGroupBox("系统状态")
        status_layout = QVBoxLayout()
        
        self.status_text = QTextEdit()
        self.status_text.setMaximumHeight(120)
        self.status_text.setReadOnly(True)
        status_layout.addWidget(self.status_text)
        
        status_group.setLayout(status_layout)
        return status_group
    
    def create_button_layout(self) -> QHBoxLayout:
        """创建按钮布局"""
        button_layout = QHBoxLayout()
        
        buttons = [
            ("录入人脸", self.record_face, BUTTON_STYLES['warning']),
            ("查看员工", self.view_employees, BUTTON_STYLES['primary']),
            ("考勤记录", self.view_attendance, BUTTON_STYLES['info']),
            ("打开摄像头", self.toggle_camera, BUTTON_STYLES['success']),
            ("导出数据", self.export_attendance, BUTTON_STYLES['secondary'])
        ]
        
        for text, slot, style in buttons:
            btn = QPushButton(text)
            btn.clicked.connect(slot)
            btn.setStyleSheet(style)
            if text == "打开摄像头":
                self.camera_btn = btn
            button_layout.addWidget(btn)
        
        return button_layout
    
    def create_right_panel(self) -> QWidget:
        """创建右侧面板"""
        right_widget = QWidget()
        right_layout = QVBoxLayout(right_widget)
        
        # 今日考勤统计
        stats_group = self.create_stats_group()
        right_layout.addWidget(stats_group)
        
        # 今日打卡详情
        attendance_group = self.create_attendance_group()
        right_layout.addWidget(attendance_group)
        
        # 刷新按钮
        refresh_btn = QPushButton("刷新打卡记录")
        refresh_btn.clicked.connect(self.refresh_attendance)
        refresh_btn.setStyleSheet("""
            QPushButton {
                padding: 8px;
                font-weight: bold;
                background-color: #009688;
                color: white;
                border-radius: 5px;
            }
            QPushButton:hover {
                background-color: #00796B;
            }
        """)
        right_layout.addWidget(refresh_btn)
        
        return right_widget
    
    def create_stats_group(self) -> QGroupBox:
        """创建统计组"""
        stats_group = QGroupBox("今日考勤统计")
        stats_layout = QVBoxLayout()
        
        self.stats_label = QLabel()
        self.stats_label.setStyleSheet("font-size: 14px; font-weight: bold;")
        stats_layout.addWidget(self.stats_label)
        
        stats_group.setLayout(stats_layout)
        return stats_group
    
    def create_attendance_group(self) -> QGroupBox:
        """创建考勤组"""
        attendance_group = QGroupBox("今日打卡详情")
        attendance_layout = QVBoxLayout()
        
        self.attendance_table = QTableWidget()
        self.attendance_table.setColumnCount(4)
        self.attendance_table.setHorizontalHeaderLabels(["姓名", "工号", "打卡时间", "状态"])
        attendance_layout.addWidget(self.attendance_table)
        
        attendance_group.setLayout(attendance_layout)
        return attendance_group
    
    def setup_timer(self):
        """设置定时器"""
        self.timer = QTimer()
        self.timer.timeout.connect(self.update_frame)
    
    def load_initial_data(self):
        """加载初始数据"""
        self.update_status("系统已启动，请打开摄像头开始使用")
        self.update_attendance_display()
    
    def update_status(self, message: str):
        """更新状态信息"""
        timestamp = datetime.datetime.now().strftime("%H:%M:%S")
        self.status_text.append(f"[{timestamp}] {message}")
        self.status_text.verticalScrollBar().setValue(
            self.status_text.verticalScrollBar().maximum()
        )
    
    def update_attendance_display(self):
        """更新考勤显示"""
        # 更新统计信息
        stats = self.controller.get_attendance_stats()
        stats_text = f"总员工数: {stats['total']}人 | 已打卡: {stats['checked_in']}人 | 未打卡: {stats['not_checked_in']}人"
        if stats['total'] > 0:
            stats_text += f" | 打卡率: {stats['attendance_rate']:.1f}%"
        
        self.stats_label.setText(stats_text)
        
        # 更新表格
        known_faces = self.controller.face_model.get_known_faces()
        today_attendance = self.controller.get_today_attendance()
        
        self.attendance_table.setRowCount(len(known_faces))
        
        row = 0
        for employee_id, face_data in known_faces.items():
            name = face_data['name']
            
            # 设置姓名和工号
            self.attendance_table.setItem(row, 0, QTableWidgetItem(name))
            self.attendance_table.setItem(row, 1, QTableWidgetItem(employee_id))
            
            # 设置打卡时间和状态
            if employee_id in today_attendance:
                attendance = today_attendance[employee_id]
                self.attendance_table.setItem(row, 2, QTableWidgetItem(attendance['check_in_time']))
                self.attendance_table.setItem(row, 3, QTableWidgetItem(attendance['status']))
                
                # 设置行颜色 - 已打卡为绿色
                for col in range(4):
                    item = self.attendance_table.item(row, col)
                    if item:
                        item.setBackground(QColor(*COLORS['attended']))
            else:
                self.attendance_table.setItem(row, 2, QTableWidgetItem("未打卡"))
                self.attendance_table.setItem(row, 3, QTableWidgetItem("未到"))
                
                # 设置行颜色 - 未打卡为浅红色
                for col in range(4):
                    item = self.attendance_table.item(row, col)
                    if item:
                        item.setBackground(QColor(*COLORS['not_attended']))
            
            row += 1
    
    def update_frame(self):
        """更新摄像头画面"""
        ret, frame = self.controller.camera_manager.read_frame()
        if ret:
            # 处理帧
            processed_frame, message = self.controller.process_frame(frame)
            
            # 显示消息
            if message:
                self.update_status(message)
            
            # 显示画面
            h, w, ch = processed_frame.shape
            bytes_per_line = ch * w
            convert_to_qt_format = QImage(processed_frame.data, w, h, bytes_per_line, QImage.Format.Format_BGR888)
            p = convert_to_qt_format.scaled(*UI_CONFIG['camera_preview_size'], Qt.AspectRatioMode.KeepAspectRatio)
            self.camera_label.setPixmap(QPixmap.fromImage(p))
    
    def toggle_camera(self):
        """切换摄像头状态"""
        if self.controller.camera_manager.is_camera_on:
            # 关闭摄像头
            self.timer.stop()
            self.controller.camera_manager.close_camera()
            self.camera_label.setText("摄像头已关闭")
            self.camera_btn.setText("打开摄像头")
            self.update_status("摄像头已关闭")
        else:
            # 打开摄像头
            if self.controller.camera_manager.open_camera():
                self.timer.start(30)  # 约30fps
                self.camera_btn.setText("关闭摄像头")
                self.update_status("摄像头已开启")
            else:
                QMessageBox.warning(self, "警告", "无法打开摄像头")
    
    def manual_check_in(self):
        """手动打卡"""
        known_faces = self.controller.face_model.get_known_faces()
        if not known_faces:
            QMessageBox.warning(self, "警告", "请先录入员工信息")
            return
        
        dialog = QDialog(self)
        dialog.setWindowTitle("手动打卡")
        dialog.setFixedSize(300, 100)
        layout = QVBoxLayout(dialog)
        
        # 员工选择下拉框
        employee_combo = QComboBox()
        for employee_id, data in known_faces.items():
            employee_combo.addItem(f"{data['name']} ({employee_id})", employee_id)
        
        layout.addWidget(QLabel("选择员工:"))
        layout.addWidget(employee_combo)
        
        buttons = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok |
                                   QDialogButtonBox.StandardButton.Cancel)
        buttons.accepted.connect(dialog.accept)
        buttons.rejected.connect(dialog.reject)
        layout.addWidget(buttons)
        
        if dialog.exec() == QDialog.DialogCode.Accepted:
            employee_id = employee_combo.currentData()
            employee_name = known_faces[employee_id]['name']
            result = self.controller.record_attendance(employee_id, employee_name)
            if result:
                self.update_status(result)
                self.update_attendance_display()
    
    def record_face(self):
        """录入人脸信息"""
        # 检查摄像头是否已开启
        if not self.controller.camera_manager.is_camera_on:
            QMessageBox.warning(self, "警告", "请先开启摄像头再进行员工录入！")
            return
        
        dialog = QDialog(self)
        dialog.setWindowTitle("录入人脸信息")
        dialog.setFixedSize(400, 200)
        
        layout = QFormLayout(dialog)
        
        name_input = QLineEdit()
        employee_id_input = QLineEdit()
        
        layout.addRow("姓名:", name_input)
        layout.addRow("工号:", employee_id_input)
        
        buttons = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok |
                                   QDialogButtonBox.StandardButton.Cancel)
        buttons.accepted.connect(dialog.accept)
        buttons.rejected.connect(dialog.reject)
        layout.addRow(buttons)
        
        if dialog.exec() == QDialog.DialogCode.Accepted:
            name = name_input.text().strip()
            employee_id = employee_id_input.text().strip()
            
            if not name or not employee_id:
                QMessageBox.warning(self, "警告", "姓名和工号不能为空")
                return
            
            # 检查工号是否已存在
            if self.controller.db_manager.check_employee_exists(employee_id):
                QMessageBox.warning(self, "警告", "该工号已存在")
                return
            
            # 使用已开启的摄像头拍摄照片
            ret, frame = self.controller.camera_manager.read_frame()
            
            if not ret:
                QMessageBox.warning(self, "警告", "拍摄照片失败")
                return
            
            # 检测人脸
            faces = self.controller.face_model.detect_faces(frame)
            
            if len(faces) == 0:
                QMessageBox.warning(self, "警告", "未检测到人脸，请重试")
                return
            
            # 提取最大的人脸
            x, y, w, h = max(faces, key=lambda rect: rect[2] * rect[3])
            face_roi = frame[y:y + h, x:x + w]
            
            # 添加员工
            success = self.controller.add_employee(name, employee_id, face_roi)
            
            if success:
                self.update_status(f" 成功录入 {name} 的人脸信息")
                self.update_attendance_display()
            else:
                QMessageBox.warning(self, "警告", "录入失败")
    
    def view_employees(self):
        """查看员工信息"""
        try:
            dialog = QDialog(self)
            dialog.setWindowTitle("员工信息")
            dialog.setFixedSize(500, 400)
            
            layout = QVBoxLayout(dialog)
            
            table = QTableWidget()
            table.setColumnCount(3)
            table.setHorizontalHeaderLabels(["姓名", "工号", "录入时间"])
            
            employees = self.controller.get_all_employees()
            
            if not employees:
                QMessageBox.information(self, "提示", "暂无员工信息")
                return
            
            table.setRowCount(len(employees))
            for row, employee_data in enumerate(employees):
                try:
                    # 处理不同长度的数据（兼容4个字段和5个字段）
                    if len(employee_data) == 4:
                        name, employee_id, _, _ = employee_data
                        created_date = "未知"
                    elif len(employee_data) == 5:
                        name, employee_id, _, _, created_date = employee_data
                    else:
                        print(f"警告: 员工数据字段数量不正确: {len(employee_data)}")
                        continue
                    
                    table.setItem(row, 0, QTableWidgetItem(str(name) if name else ""))
                    table.setItem(row, 1, QTableWidgetItem(str(employee_id) if employee_id else ""))
                    table.setItem(row, 2, QTableWidgetItem(str(created_date) if created_date else "未知"))
                except Exception as e:
                    print(f"处理员工数据时出错: {e}")
                    continue
            
            table.resizeColumnsToContents()
            layout.addWidget(table)
            
            close_btn = QPushButton("关闭")
            close_btn.clicked.connect(dialog.accept)
            layout.addWidget(close_btn)
            
            dialog.exec()
            
        except Exception as e:
            print(f"查看员工信息时出错: {e}")
            QMessageBox.critical(self, "错误", f"查看员工信息失败: {str(e)}")
    
    def view_attendance(self):
        """查看考勤记录"""
        dialog = QDialog(self)
        dialog.setWindowTitle("考勤记录查询")
        dialog.setFixedSize(600, 500)
        
        layout = QVBoxLayout(dialog)
        
        # 日期选择区域
        date_layout = QHBoxLayout()
        date_layout.addWidget(QLabel("选择日期:"))
        
        date_edit = QLineEdit(datetime.datetime.now().strftime("%Y-%m-%d"))
        date_layout.addWidget(date_edit)
        
        query_btn = QPushButton("查询")
        date_layout.addWidget(query_btn)
        
        layout.addLayout(date_layout)
        
        # 表格区域
        table = QTableWidget()
        table.setColumnCount(4)
        table.setHorizontalHeaderLabels(["姓名", "工号", "打卡时间", "状态"])
        layout.addWidget(table)
        
        def query_attendance():
            date = date_edit.text().strip()
            records = self.controller.db_manager.get_attendance_by_date(date)
            
            table.setRowCount(len(records))
            
            for row, (employee_id, name, check_in_time, status) in enumerate(records):
                table.setItem(row, 0, QTableWidgetItem(name))
                table.setItem(row, 1, QTableWidgetItem(employee_id))
                table.setItem(row, 2, QTableWidgetItem(check_in_time))
                table.setItem(row, 3, QTableWidgetItem(status))
            
            table.resizeColumnsToContents()
        
        query_btn.clicked.connect(query_attendance)
        query_attendance()  # 初始查询
        
        close_btn = QPushButton("关闭")
        close_btn.clicked.connect(dialog.accept)
        layout.addWidget(close_btn)
        
        dialog.exec()
    
    def export_attendance(self):
        """导出考勤数据"""
        # 选择日期范围
        dialog = QDialog(self)
        dialog.setWindowTitle("导出考勤数据")
        dialog.setFixedSize(300, 150)
        
        layout = QFormLayout(dialog)
        
        start_date = QLineEdit((datetime.datetime.now() - datetime.timedelta(days=7)).strftime("%Y-%m-%d"))
        end_date = QLineEdit(datetime.datetime.now().strftime("%Y-%m-%d"))
        
        layout.addRow("开始日期:", start_date)
        layout.addRow("结束日期:", end_date)
        
        buttons = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok |
                                   QDialogButtonBox.StandardButton.Cancel)
        buttons.accepted.connect(dialog.accept)
        buttons.rejected.connect(dialog.reject)
        layout.addRow(buttons)
        
        if dialog.exec() != QDialog.DialogCode.Accepted:
            return
        
        # 选择保存路径
        file_path, _ = QFileDialog.getSaveFileName(
            self, "保存考勤数据", "考勤记录.csv", "CSV文件 (*.csv)"
        )
        
        if not file_path:
            return
        
        success = self.controller.export_attendance_data(start_date.text(), end_date.text(), file_path)
        
        if success:
            self.update_status(f" 考勤数据已导出到: {file_path}")
            QMessageBox.information(self, "成功", f"考勤数据已导出到: {file_path}")
        else:
            self.update_status(f" 导出失败")
            QMessageBox.critical(self, "错误", "导出失败")
    
    def refresh_attendance(self):
        """刷新考勤记录"""
        self.controller.load_today_attendance()
        self.update_attendance_display()
        self.update_status("考勤记录已刷新")
    
    def closeEvent(self, event):
        """关闭事件"""
        self.controller.close()
        self.update_status("系统已关闭")
        event.accept()
